

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=light>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/set/B.svg">
  <link rel="icon" href="/img/set/B.svg">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="author" content="程守斌">
  <meta name="keywords" content="">
  
    <meta name="description" content="iOS 各种锁锁的类别 自旋锁  自旋锁是一种多线程同步机制，它是一种忙等待的实现方式，即线程在获取锁的时候，如果发现锁已经被其他线程占有，则不断地进行忙等待，直到获取到锁为止。在获取锁的过程中，线程会一直占用 CPU 时间，不会让出 CPU，因此会浪费 CPU 资源。  适用场景 适用于被占用时间短的临界区。如果临界区的代码执行时间过长，使用自旋锁会浪费大量的 CPU 资源，不如使用互斥锁等待被">
<meta property="og:type" content="article">
<meta property="og:title" content="iOS 各种锁">
<meta property="og:url" content="https://icoobin.github.io/2023/03/22/ios/iOS-%E5%90%84%E7%A7%8D%E9%94%81/index.html">
<meta property="og:site_name" content="Bin&#39;s blog">
<meta property="og:description" content="iOS 各种锁锁的类别 自旋锁  自旋锁是一种多线程同步机制，它是一种忙等待的实现方式，即线程在获取锁的时候，如果发现锁已经被其他线程占有，则不断地进行忙等待，直到获取到锁为止。在获取锁的过程中，线程会一直占用 CPU 时间，不会让出 CPU，因此会浪费 CPU 资源。  适用场景 适用于被占用时间短的临界区。如果临界区的代码执行时间过长，使用自旋锁会浪费大量的 CPU 资源，不如使用互斥锁等待被">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://icoobin.github.io/img/index/ios-lock.png">
<meta property="article:published_time" content="2023-03-22T04:31:31.000Z">
<meta property="article:modified_time" content="2023-03-22T13:42:50.379Z">
<meta property="article:author" content="程守斌">
<meta property="article:tag" content="iOS">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://icoobin.github.io/img/index/ios-lock.png">
  
  
    <meta name="referrer" content="no-referrer-when-downgrade">
  
  
  <title>iOS 各种锁 - Bin&#39;s blog</title>

  <link  rel="stylesheet" href="https://lib.baomitu.com/twitter-bootstrap/4.6.1/css/bootstrap.min.css" />



  <link  rel="stylesheet" href="https://lib.baomitu.com/github-markdown-css/4.0.0/github-markdown.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/hint.css/2.7.0/hint.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.css" />



<!-- 主题依赖的图标库，不要自行修改 -->
<!-- Do not modify the link that theme dependent icons -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_hj8rtnfg7um.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_lbnruvf0jn.css">


<link  rel="stylesheet" href="/css/main.css" />


  <link id="highlight-css" rel="stylesheet" href="/css/highlight.css" />
  
    <link id="highlight-css-dark" rel="stylesheet" href="/css/highlight-dark.css" />
  




  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    Fluid.ctx = Object.assign({}, Fluid.ctx)
    var CONFIG = {"hostname":"icoobin.github.io","root":"/","version":"1.9.4","typing":{"enable":true,"typeSpeed":70,"cursorChar":"|","loop":false,"scope":["home","post"]},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"left","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"code_language":{"enable":true,"default":"TEXT"},"copy_btn":true,"image_caption":{"enable":true},"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"placement":"right","headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/set/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":true,"follow_dnt":true,"baidu":"0424c6a81239810100c98bd470a50118","google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null,"path":"window.location.pathname","ignore_local":false}},"search_path":"/local-search.xml"};

    if (CONFIG.web_analytics.follow_dnt) {
      var dntVal = navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack;
      Fluid.ctx.dnt = dntVal && (dntVal.startsWith('1') || dntVal.startsWith('yes') || dntVal.startsWith('on'));
    }
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
  

  
    <!-- Baidu Analytics -->
    <script async>
      if (!Fluid.ctx.dnt) {
        var _hmt = _hmt || [];
        (function() {
          var hm = document.createElement("script");
          hm.src = "https://hm.baidu.com/hm.js?0424c6a81239810100c98bd470a50118";
          var s = document.getElementsByTagName("script")[0];
          s.parentNode.insertBefore(hm, s);
        })();
      }
    </script>
  

  

  

  

  

  

  



  
<meta name="generator" content="Hexo 5.4.2"></head>


<body>
  

  <header>
    

<div class="header-inner" style="height: 38.2vh;">
  <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/">
      <strong>Bin&#39;s blog</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                <span>首页</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                <span>归档</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                <span>分类</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                <span>标签</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                <span>关于</span>
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              <i class="iconfont icon-search"></i>
            </a>
          </li>
          
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">
              <i class="iconfont icon-dark" id="color-toggle-icon"></i>
            </a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

  

<div id="banner" class="banner" parallax=true
     style="background: url('/img/banner/posts.jpg') no-repeat center center; background-size: cover;">
  <div class="full-bg-img">
    <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
      <div class="banner-text text-center fade-in-up">
        <div class="h2">
          
            <span id="subtitle" data-typed-text="iOS 各种锁"></span>
          
        </div>

        
          
  <div class="mt-3">
    
    
      <span class="post-meta">
        <i class="iconfont icon-date-fill" aria-hidden="true"></i>
        <time datetime="2023-03-22 12:31" pubdate>
          2023年3月22日 下午
        </time>
      </span>
    
  </div>

  <div class="mt-1">
    
      <span class="post-meta mr-2">
        <i class="iconfont icon-chart"></i>
        
          5.8k 字
        
      </span>
    

    
      <span class="post-meta mr-2">
        <i class="iconfont icon-clock-fill"></i>
        
        
        
          49 分钟
        
      </span>
    

    
    
      
        <span id="busuanzi_container_page_pv" style="display: none">
          <i class="iconfont icon-eye" aria-hidden="true"></i>
          <span id="busuanzi_value_page_pv"></span> 次
        </span>
        
      
    
  </div>


        
      </div>

      
    </div>
  </div>
</div>

</div>

  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="side-col d-none d-lg-block col-lg-2">
      

    </div>

    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">iOS 各种锁</h1>
            
            
              <div class="markdown-body">
                
                <h2 id="iOS-各种锁"><a href="#iOS-各种锁" class="headerlink" title="iOS 各种锁"></a>iOS 各种锁</h2><h3 id="锁的类别"><a href="#锁的类别" class="headerlink" title="锁的类别"></a>锁的类别</h3><ul>
<li><p>自旋锁<br>  自旋锁是一种多线程同步机制，它是一种忙等待的实现方式，即线程在获取锁的时候，如果发现锁已经被其他线程占有，则不断地进行忙等待，直到获取到锁为止。在获取锁的过程中，线程会一直占用 CPU 时间，不会让出 CPU，因此会浪费 CPU 资源。</p>
<ul>
<li>适用场景<ul>
<li>适用于被占用时间短的临界区。如果临界区的代码执行时间过长，使用自旋锁会浪费大量的 CPU 资源，不如使用互斥锁等待被唤醒。</li>
<li>适用于多核 CPU 系统。在单核 CPU 系统中，自旋锁会一直占用 CPU 时间，其他线程无法执行，会导致性能下降。</li>
</ul>
</li>
<li>不适用场景<ul>
<li>不适用于被占用时间长的临界区。在临界区代码执行时间长的情况下，自旋锁会一直占用 CPU 时间，浪费大量资源，不如使用互斥锁等待被唤醒。</li>
<li>不适用于单核 CPU 系统。在单核 CPU 系统中，自旋锁会一直占用 CPU 时间，其他线程无法执行，会导致性能下降。在单核 CPU 系统中，应该使用互斥锁等待被唤醒。</li>
</ul>
</li>
</ul>
</li>
<li><p>互斥锁<br>  互斥锁是一种同步机制，用于控制多个线程对共享资源的访问。当一个线程获得了互斥锁时，其他线程就不能再获得该锁，直到该线程释放锁。这样可以确保同一时间只有一个线程能够访问共享资源，从而避免多个线程同时修改同一个资源而导致数据不一致的问题。</p>
<ul>
<li>适用场景<ul>
<li>多个线程需要共享同一份资源，如文件、数据库连接、共享内存等。</li>
<li>多个线程需要访问同一个对象或变量。</li>
</ul>
</li>
<li>不适用场景<ul>
<li>资源竞争不激烈的情况下，使用互斥锁会带来额外的开销。</li>
<li>在单线程环境下，互斥锁没有任何意义，反而会增加代码的复杂度和运行时间。</li>
</ul>
</li>
</ul>
</li>
<li><p>递归锁<br>  递归锁是一种线程同步机制，用于在多线程代码中保护共享资源。与普通的锁相比，递归锁允许同一线程多次获取同一把锁，而不会导致死锁。递归锁通常用于需要在同一线程中嵌套调用的情况下，以避免竞争条件。</p>
<ul>
<li>适用场景<ul>
<li>当需要在同一线程中嵌套调用时，使用递归锁可以避免死锁。</li>
<li>当一个线程需要多次获取同一把锁时，使用递归锁可以保证正确性。</li>
</ul>
</li>
<li>不适用场景<ul>
<li>当使用递归锁导致代码变得复杂或难以理解时，不应该使用递归锁。</li>
<li>当需要在多个线程之间共享锁时，递归锁可能不是最好的选择，因为它只能在同一线程中保证正确性。</li>
</ul>
</li>
</ul>
</li>
<li><p>读写锁<br>  读写锁是一种多线程同步机制，它允许对共享资源的并发读取，同时防止写入时的竞争。在读多写少的场景下，使用读写锁可以提高并发性能。</p>
<ul>
<li>适用场景<ul>
<li>共享资源被频繁读取，写入较少。</li>
<li>需要对共享资源进行读取和写入的线程数量很多。</li>
</ul>
</li>
<li>不适用场景<ul>
<li>共享资源被频繁写入。</li>
<li>写入操作的时间很长，会阻塞其他线程的读取操作，导致性能下降。</li>
</ul>
</li>
</ul>
</li>
<li><p>条件锁<br>  条件锁（Condition Lock）是一种多线程同步机制，用于在等待某个条件成立时暂停线程并释放锁，等到条件成立后再继续执行线程</p>
<ul>
<li>适用场景<ul>
<li>需要等待某个条件成立才能执行后续操作的情况，例如生产者消费者模型，线程池等。</li>
</ul>
</li>
<li>不适用场景<ul>
<li>需要频繁等待的情况，因为等待会增加上下文切换的开销，降低程序的性能。</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="自旋锁"><a href="#自旋锁" class="headerlink" title="自旋锁"></a>自旋锁</h3><ul>
<li>OSSpinLock <code>#import &lt;libkern/OSAtomic.h&gt;</code> <code>iOS 10 已弃用</code><ul>
<li>因为它可能会导致优先级反转、线程饥饿问题。而被弃用</li>
</ul>
</li>
<li>atomic <code>spinlock_t</code></li>
</ul>
<div class="code-wrapper"><pre><code class="hljs objc">
<span class="hljs-comment">///1. OSSpinLock</span>
OSSpinLock spinLock = OS_SPINLOCK_INIT;

OSSpinLockLock(&amp;spinLock);
<span class="hljs-comment">/// 临界区</span>
OSSpinLockUnlock(&amp;spinLock);


<span class="hljs-comment">///2. atomic</span>
<span class="hljs-keyword">@property</span> (atomic, <span class="hljs-keyword">assign</span>) <span class="hljs-type">int</span> age;
<span class="hljs-comment">///在 objc-accessors.mm 源码文件中，atomic 使用的是 spinlock_t</span>
</code></pre></div>

<h3 id="互斥锁"><a href="#互斥锁" class="headerlink" title="互斥锁"></a>互斥锁</h3><ul>
<li>os_unfair_lock <code>替代 OSSpinLock</code> <code>Low-Level Lock</code> <code>等待时休眠具有互斥性</code></li>
<li>semaphore_t</li>
<li>mutex_t <code>PTHREAD_MUTEX_DEFAULT</code></li>
<li>NSLock</li>
</ul>
<div class="code-wrapper"><pre><code class="hljs objc"><span class="hljs-comment">/// 1.os_unfair_lock</span>
os_unfair_lock unfailLock = OS_UNFAIR_LOCK_INIT;

<span class="hljs-comment">/// 如果没拿到锁，返回 false，线程继续执行</span>
<span class="hljs-keyword">if</span> (os_unfair_lock_trylock(&amp;unfailLock)) &#123;

    <span class="hljs-comment">/// 临界区 ...</span>

    os_unfair_lock_unlock(&amp;unfailLock);
&#125;

<span class="hljs-comment">/// 如果没拿到锁，线程将休眠</span>
os_unfair_lock_lock(&amp;unfailLock);
<span class="hljs-comment">/// 临界区 ...</span>
os_unfair_lock_unlock(&amp;unfailLock);


<span class="hljs-comment">/// 2. semaphore_t</span>
dispatch_semaphore_t semaphore = dispatch_semaphore_create(<span class="hljs-number">1</span>);

<span class="hljs-comment">/// semaphore &lt;=0 时，线程将等待</span>
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

<span class="hljs-comment">/// 临界区 ...</span>

dispatch_semaphore_signal(semaphore); 


<span class="hljs-comment">/// 3. mutex_t 互斥锁，PTHREAD_MUTEX_DEFAULT</span>
pthread_mutex_t mutexLock;

<span class="hljs-comment">/// 通过 attr 创建</span>
<span class="hljs-comment">//pthread_mutexattr_t attr;</span>
<span class="hljs-comment">//pthread_mutexattr_init(&amp;attr);</span>
<span class="hljs-comment">//pthread_mutexattr_settype(&amp;attr, PTHREAD_MUTEX_DEFAULT);</span>
<span class="hljs-comment">//pthread_mutex_init(&amp;mutexLock, &amp;attr);</span>
<span class="hljs-comment">//pthread_mutexattr_destroy(&amp;attr);</span>
<span class="hljs-comment">/// NULL 等价于以上 PTHREAD_MUTEX_DEFAULT 创建</span>
pthread_mutex_init(&amp;mutexLock, <span class="hljs-literal">NULL</span>);

<span class="hljs-comment">/// 如果没有拿到锁，则线程进入休眠状态</span>
pthread_mutex_lock(&amp;mutexLock);

<span class="hljs-comment">/// 临界区 ...</span>

pthread_mutex_unlock(&amp;mutexLock);

<span class="hljs-comment">/// 释放锁</span>
pthread_mutex_destroy(&amp;mutexLock);


<span class="hljs-comment">/// 4. NSLock</span>
<span class="hljs-built_in">NSLock</span> *lock = [[<span class="hljs-built_in">NSLock</span> alloc] init];

[lock lock];

<span class="hljs-comment">/// 临界区 ...</span>

[lock unlock];
</code></pre></div>

<h3 id="递归锁"><a href="#递归锁" class="headerlink" title="递归锁"></a>递归锁</h3><ul>
<li>NSRecursiveLock</li>
<li>mutex_t  <code>PTHREAD_MUTEX_RECURSIVE</code></li>
<li>@synchronized</li>
</ul>
<div class="code-wrapper"><pre><code class="hljs objc"><span class="hljs-comment">/// 1.NSRecursiveLock</span>
<span class="hljs-built_in">NSRecursiveLock</span> *recursiveLock = [[<span class="hljs-built_in">NSRecursiveLock</span> alloc] init];

[recursiveLock lock];

<span class="hljs-comment">/// 临界区 ...</span>

[recursiveLock unlock];


<span class="hljs-comment">/// 2. mutex_t 递归锁，PTHREAD_MUTEX_RECURSIVE</span>
pthread_mutex_t mutexLock;

<span class="hljs-comment">/// 通过 attr 创建</span>
pthread_mutexattr_t attr;
pthread_mutexattr_init(&amp;attr);
<span class="hljs-comment">/// settype 设置锁类型：PTHREAD_MUTEX_RECURSIVE 递归锁</span>
pthread_mutexattr_settype(&amp;attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&amp;mutexLock, &amp;attr);
pthread_mutexattr_destroy(&amp;attr);

<span class="hljs-comment">/// 如果没有拿到锁，则线程进入休眠状态</span>
pthread_mutex_lock(&amp;mutexLock);

<span class="hljs-comment">/// 临界区 ...</span>

pthread_mutex_unlock(&amp;mutexLock);

<span class="hljs-comment">/// 释放锁</span>
pthread_mutex_destroy(&amp;mutexLock);


<span class="hljs-comment">/// 3. @synchronized</span>
<span class="hljs-keyword">@synchronized</span> (<span class="hljs-keyword">self</span>) &#123;
    
    <span class="hljs-comment">/// 临界区 ...</span>
    
&#125;</code></pre></div>

<h3 id="读写锁"><a href="#读写锁" class="headerlink" title="读写锁"></a>读写锁</h3><ul>
<li>pthread_rwlock_t</li>
<li>dispatch_barrier_async <code>DISPATCH_QUEUE_CONCURRENT</code></li>
</ul>
<div class="code-wrapper"><pre><code class="hljs objc"><span class="hljs-comment">/// 1. pthread_rwlock_t</span>
pthread_rwlock_t _rwLock;
pthread_rwlock_init(&amp;_rwLock, <span class="hljs-literal">NULL</span>);

<span class="hljs-comment">/// 如果使用 GCD 很可能分配的是相同线程，所有不好区分</span>
<span class="hljs-comment">/// 读写锁测试时最好手动创建线程才比较好区分</span>

<span class="hljs-comment">/// 写锁，只能一个写，会看到 sleep | Awake 是连续出现的</span>
<span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>; i&lt;<span class="hljs-number">10</span>; i++) &#123;
    [[[<span class="hljs-built_in">NSThread</span> alloc] initWithBlock:^&#123;
        <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>; i&lt;<span class="hljs-number">5</span>; i++) &#123;
            pthread_rwlock_wrlock(&amp;_rwLock);
            <span class="hljs-built_in">NSLog</span>(<span class="hljs-string">@&quot;write, begin sleep，%@&quot;</span>, [<span class="hljs-built_in">NSThread</span> currentThread]);
            sleep(<span class="hljs-number">0.5</span>);
            <span class="hljs-built_in">NSLog</span>(<span class="hljs-string">@&quot;write, begin Awake，%@&quot;</span>, [<span class="hljs-built_in">NSThread</span> currentThread]);
            pthread_rwlock_unlock(&amp;_rwLock);
        &#125;
    &#125;] start];
&#125;

<span class="hljs-comment">/// 读锁，应该都能读，会有看到多个 sleep 连续打印</span>
<span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>; i&lt;<span class="hljs-number">10</span>; i++) &#123;
    [[[<span class="hljs-built_in">NSThread</span> alloc] initWithBlock:^&#123;
        <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>; i&lt;<span class="hljs-number">5</span>; i++) &#123;
            pthread_rwlock_rdlock(&amp;_rwLock);
            <span class="hljs-built_in">NSLog</span>(<span class="hljs-string">@&quot;read, begin sleep，%@&quot;</span>, [<span class="hljs-built_in">NSThread</span> currentThread]);
            sleep(<span class="hljs-number">0.5</span>);
            <span class="hljs-built_in">NSLog</span>(<span class="hljs-string">@&quot;read, begin Awake，%@&quot;</span>, [<span class="hljs-built_in">NSThread</span> currentThread]);
            pthread_rwlock_unlock(&amp;_rwLock);
        &#125;
    &#125;] start];
&#125;


<span class="hljs-comment">/// 2.dispatch_barrier_async 实现读写锁功能</span>
<span class="hljs-comment">/// barrier 要实现读写锁功能，必须手动创建一个 CONCURRENT 的并发队列</span>
<span class="hljs-comment">/// 不能使用却句的并发队列</span>
<span class="hljs-comment">/// 如果使用全局的并发队列，那 barrier 函数等同于 dispatch_async 函数的效果</span>
<span class="hljs-comment">///  XXX : dispatch_queue_t queue = dispatch_get_global_queue(0, 0); &#123;不能使用这个&#125;</span>
<span class="hljs-comment">/// 初始化队列</span>
<span class="hljs-built_in">dispatch_queue_t</span> queue = dispatch_queue_create(<span class="hljs-string">&quot;rw_queue&quot;</span>, DISPATCH_QUEUE_CONCURRENT);

<span class="hljs-comment">/// 读</span>
<span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>; i&lt;<span class="hljs-number">10</span>; i++) &#123;
    <span class="hljs-built_in">dispatch_async</span>(queue, ^&#123;
        <span class="hljs-built_in">NSLog</span>(<span class="hljs-string">@&quot;read, begin sleep，%@&quot;</span>, [<span class="hljs-built_in">NSThread</span> currentThread]);
        sleep(<span class="hljs-number">0.5</span>);
        <span class="hljs-built_in">NSLog</span>(<span class="hljs-string">@&quot;read, begin Awake，%@&quot;</span>, [<span class="hljs-built_in">NSThread</span> currentThread]);
    &#125;);
&#125;

<span class="hljs-comment">/// 写</span>
<span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>; i&lt;<span class="hljs-number">10</span>; i++) &#123;
    dispatch_barrier_async(queue, ^&#123;
        <span class="hljs-built_in">NSLog</span>(<span class="hljs-string">@&quot;write, begin sleep，%@&quot;</span>, [<span class="hljs-built_in">NSThread</span> currentThread]);
        sleep(<span class="hljs-number">0.5</span>);
        <span class="hljs-built_in">NSLog</span>(<span class="hljs-string">@&quot;write, begin Awake，%@&quot;</span>, [<span class="hljs-built_in">NSThread</span> currentThread]);
    &#125;);
&#125;
</code></pre></div>

<h3 id="条件锁"><a href="#条件锁" class="headerlink" title="条件锁"></a>条件锁</h3><ul>
<li>NSCondition</li>
<li>NSConditionLock</li>
</ul>
<div class="code-wrapper"><pre><code class="hljs objc"><span class="hljs-comment">/// 1. NSCondition</span>
<span class="hljs-built_in">NSCondition</span> *lock = [[<span class="hljs-built_in">NSCondition</span> alloc] init];
<span class="hljs-built_in">NSInteger</span> productCount = <span class="hljs-number">0</span>;
<span class="hljs-comment">/// 消费者：线程1 wait</span>
[lock lock];
<span class="hljs-keyword">if</span> (productCount &lt;= <span class="hljs-number">0</span>) &#123;
    [lock wait];
&#125;
productCount -= <span class="hljs-number">1</span>;
[lock unlock];

<span class="hljs-comment">/// 生产者：线程2 signal</span>
[lock lock];
productCount += <span class="hljs-number">1</span>;
<span class="hljs-keyword">if</span> (productCount &gt; <span class="hljs-number">0</span>) &#123;
    [lock signal];
&#125;
[lock unlock];


<span class="hljs-comment">/// 2. NSConditionLock</span>
<span class="hljs-comment">/// NSConditionLock 适用于有先后顺序等多道工序的多线程场景</span>
<span class="hljs-built_in">NSConditionLock</span> *condLock = [[<span class="hljs-built_in">NSConditionLock</span> alloc] initWithCondition:<span class="hljs-number">1</span>];

<span class="hljs-comment">/// 工序 0：线程 0 。于其他工序无关，就不需要 condition</span>
[condLock lock];

<span class="hljs-comment">/// 工序 0 临界区 ...</span>
<span class="hljs-comment">/// 解锁时可设置当前条件</span>
[condLock unlockWithCondition:<span class="hljs-number">1</span>];

<span class="hljs-comment">/// 工序1：线程 1。需要 condtion == 1 时才能拿到锁，否则睡眠等待</span>
[condLock lockWhenCondition:<span class="hljs-number">1</span>];

<span class="hljs-comment">/// 工序1 临界区 ...</span>

[condLock unlockWithCondition:<span class="hljs-number">2</span>];

<span class="hljs-comment">/// 工序2：线程 2。需要 condtion == 2 时才能拿到锁，否则睡眠等待</span>
[condLock lockWhenCondition:<span class="hljs-number">2</span>];

<span class="hljs-comment">/// 工序2 临界区 ...</span>

[condLock unlockWithCondition:<span class="hljs-number">1</span>];<span class="hljs-comment">///解锁时可设置为 1，则线程 1可被唤醒工作。</span>
</code></pre></div>

<h3 id="锁性能"><a href="#锁性能" class="headerlink" title="锁性能"></a>锁性能</h3><ul>
<li>os_unfair_lock 替代 OSSpinLock</li>
</ul>
<p><img src="/img/posts/ios/ios-lock-performance.png" srcset="/img/set/loading.gif" lazyload></p>

                
              </div>
            
            <hr/>
            <div>
              <div class="post-metas my-3">
  
    <div class="post-meta mr-3 d-flex align-items-center">
      <i class="iconfont icon-category"></i>
      

<span class="category-chains">
  
  
    
      <span class="category-chain">
        
  <a href="/categories/iOS/" class="category-chain-item">iOS</a>
  
  

      </span>
    
  
</span>

    </div>
  
  
    <div class="post-meta">
      <i class="iconfont icon-tags"></i>
      
        <a href="/tags/iOS/">#iOS</a>
      
    </div>
  
</div>


              
  

  <div class="license-box my-3">
    <div class="license-title">
      <div>iOS 各种锁</div>
      <div>https://icoobin.github.io/2023/03/22/ios/iOS-各种锁/</div>
    </div>
    <div class="license-meta">
      
        <div class="license-meta-item">
          <div>作者</div>
          <div>程守斌</div>
        </div>
      
      
        <div class="license-meta-item license-meta-date">
          <div>发布于</div>
          <div>2023年3月22日</div>
        </div>
      
      
      
        <div class="license-meta-item">
          <div>许可协议</div>
          <div>
            
              
              
                <a target="_blank" href="https://creativecommons.org/licenses/by/4.0/">
                  <span class="hint--top hint--rounded" aria-label="BY - 署名">
                    <i class="iconfont icon-by"></i>
                  </span>
                </a>
              
            
          </div>
        </div>
      
    </div>
    <div class="license-icon iconfont"></div>
  </div>



              
                <div class="post-prevnext my-3">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2023/03/23/iOS%20%E4%B9%8B%20NSProxy/" title="iOS 之 NSProxy">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">iOS 之 NSProxy</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2023/03/22/other/LeetCode-%E5%88%B7%E9%A2%98%E6%8F%92%E4%BB%B6%EF%BC%8C%E5%A5%BD%E7%94%A8/" title="LeetCode 刷题插件，好用">
                        <span class="hidden-mobile">LeetCode 刷题插件，好用</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
          </article>
        </div>
      </div>
    </div>

    <div class="side-col d-none d-lg-block col-lg-2">
      
  <aside class="sidebar" style="margin-left: -1rem">
    <div id="toc">
  <p class="toc-header">
    <i class="iconfont icon-list"></i>
    <span>目录</span>
  </p>
  <div class="toc-body" id="toc-body"></div>
</div>



  </aside>


    </div>
  </div>
</div>





  



  



  



  



  







    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v" for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>

    

    
      <div class="col-lg-7 mx-auto nopadding-x-md">
        <div class="container custom mx-auto">
           <script src="/js/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script> <script>L2Dwidget.init({ pluginRootPath: "live2dw/", pluginJsPath: "lib/", pluginModelPath: "assets/", tagMode: !1, log: !1, model: { jsonPath: "/js/live2dw/assets/hijiki.model.json" }, display: { position: "left", hOffset: 60, vOffset: 0, width: 150, height: 300 }, mobile: { show: !1 } })</script> 
        </div>
      </div>
    
  </main>

  <footer>
    <div class="footer-inner">
    
        <div class="footer-content">
             <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a> 
        </div>
        
            
                <div class="statistics">
  
  

  
    
      <span id="busuanzi_container_site_pv" style="display: none">
        总访问量 
        <span id="busuanzi_value_site_pv"></span>
         次
      </span>
    
    
      <span id="busuanzi_container_site_uv" style="display: none">
        总访客数 
        <span id="busuanzi_value_site_uv"></span>
         人
      </span>
    
    
  
</div>

                    
                        
                                    
</div>

<!-- <script src="js/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script>
<script>L2Dwidget.init({ pluginRootPath: "live2dw/", pluginJsPath: "lib/", pluginModelPath: "assets/", tagMode: !1, log: !1, model: { jsonPath: "js/live2dw/assets/hijiki.model.json" }, display: { position: "left", hOffset: 60, vOffset: 0, width: 150, height: 300 }, mobile: { show: !1 } })</script> -->

<!--
<div id="music_div" style="position: fixed; bottom: 0px; left: 30px;">
    <iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=330 height=110
        src="//music.163.com/outchain/player?type=0&id=919444742&auto=1&height=90">
    </iframe>
    <script src="https://cdn.staticfile.org/jquery/3.3.1/jquery.min.js"></script>
    <script src="/js/musicshow.js"></script>
</div>
-->

  </footer>

  <!-- Scripts -->
  
  <script  src="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://lib.baomitu.com/jquery/3.6.0/jquery.min.js" ></script>
<script  src="https://lib.baomitu.com/twitter-bootstrap/4.6.1/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>


  <script  src="https://lib.baomitu.com/typed.js/2.0.12/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var subtitle = document.getElementById('subtitle');
      if (!subtitle || !typing) {
        return;
      }
      var text = subtitle.getAttribute('data-typed-text');
      
        typing(text);
      
    })(window, document);
  </script>




  
    <script  src="/js/img-lazyload.js" ></script>
  




  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/tocbot/4.18.2/tocbot.min.js', function() {
    var toc = jQuery('#toc');
    if (toc.length === 0 || !window.tocbot) { return; }
    var boardCtn = jQuery('#board-ctn');
    var boardTop = boardCtn.offset().top;

    window.tocbot.init(Object.assign({
      tocSelector     : '#toc-body',
      contentSelector : '.markdown-body',
      linkClass       : 'tocbot-link',
      activeLinkClass : 'tocbot-active-link',
      listClass       : 'tocbot-list',
      isCollapsedClass: 'tocbot-is-collapsed',
      collapsibleClass: 'tocbot-is-collapsible',
      scrollSmooth    : true,
      includeTitleTags: true,
      headingsOffset  : -boardTop,
    }, CONFIG.toc));
    if (toc.find('.toc-list-item').length > 0) {
      toc.css('visibility', 'visible');
    }

    Fluid.events.registerRefreshCallback(function() {
      if ('tocbot' in window) {
        tocbot.refresh();
        var toc = jQuery('#toc');
        if (toc.length === 0 || !tocbot) {
          return;
        }
        if (toc.find('.toc-list-item').length > 0) {
          toc.css('visibility', 'visible');
        }
      }
    });
  });
</script>


  <script src=https://lib.baomitu.com/clipboard.js/2.0.11/clipboard.min.js></script>

  <script>Fluid.plugins.codeWidget();</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/anchor-js/4.3.1/anchor.min.js', function() {
    window.anchors.options = {
      placement: CONFIG.anchorjs.placement,
      visible  : CONFIG.anchorjs.visible
    };
    if (CONFIG.anchorjs.icon) {
      window.anchors.options.icon = CONFIG.anchorjs.icon;
    }
    var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
    var res = [];
    for (var item of el) {
      res.push('.markdown-body > ' + item.trim());
    }
    if (CONFIG.anchorjs.placement === 'left') {
      window.anchors.options.class = 'anchorjs-link-left';
    }
    window.anchors.add(res.join(', '));

    Fluid.events.registerRefreshCallback(function() {
      if ('anchors' in window) {
        anchors.removeAll();
        var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
        var res = [];
        for (var item of el) {
          res.push('.markdown-body > ' + item.trim());
        }
        if (CONFIG.anchorjs.placement === 'left') {
          anchors.options.class = 'anchorjs-link-left';
        }
        anchors.add(res.join(', '));
      }
    });
  });
</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.js', function() {
    Fluid.plugins.fancyBox();
  });
</script>


  <script>Fluid.plugins.imageCaption();</script>

  <script  src="/js/local-search.js" ></script>

  <script defer src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>





<!-- 主题的启动项，将它保持在最底部 -->
<!-- the boot of the theme, keep it at the bottom -->
<script  src="/js/boot.js" ></script>


  

  <noscript>
    <div class="noscript-warning">博客在允许 JavaScript 运行的环境下浏览效果更佳</div>
  </noscript>
</body>
</html>
